package com.heima.wemedia.service.impl;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.heima.article.feign.ApArticleFeign;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.constants.MQConstants;
import com.heima.common.constants.RedisConstants;
import com.heima.common.dtos.ResponseResult;
import com.heima.common.minio.MinIOFileStorageService;
import com.heima.model.article.dtos.ArticleDto;
import com.heima.model.wemedia.pojos.WmChannel;
import com.heima.model.wemedia.pojos.WmNews;
import com.heima.model.wemedia.pojos.WmSensitive;
import com.heima.model.wemedia.pojos.WmUser;
import com.heima.utils.common.BeanHelper;
import com.heima.utils.common.JsonUtils;
import com.heima.utils.common.SensitiveWordUtil;
import com.heima.wemedia.mapper.WmChannelMapper;
import com.heima.wemedia.mapper.WmNewsMapper;
import com.heima.wemedia.mapper.WmSensitiveMapper;
import com.heima.wemedia.mapper.WmUserMapper;
import com.heima.wemedia.service.WmNewTaskService;
import com.heima.wemedia.service.WmNewsAutoScanService;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import net.sourceforge.tess4j.ITesseract;
import net.sourceforge.tess4j.TesseractException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class WmNewsAutoScanServiceImpl implements WmNewsAutoScanService {

    @Autowired(required = false)
    private WmNewsMapper wmNewsMapper;

    @Autowired(required = false)
    private WmUserMapper wmUserMapper;

    @Autowired(required = false)
    private WmChannelMapper wmChannelMapper;

    @Autowired(required = false)
    private WmSensitiveMapper wmSensitiveMapper;

    @Autowired
    private MinIOFileStorageService storageService;

    @Autowired
    private ApArticleFeign feign;

    @Value("${minio.readPath}")
    private String readPath;

    @Autowired
    private GreenTextScan greenTextScan;

    @Autowired
    private GreenImageScan greenImageScan;

    @Autowired
    private StringRedisTemplate redisTemplate;

    @Autowired
    private ITesseract tesseract;

    @Autowired
    private WmNewTaskService wmNewTaskService;

    @Autowired
    private KafkaTemplate<String,String> kafkaTemplate;

    @Override
    @Async
    @GlobalTransactional
    public void autoScanWmNews(Integer id) {
        //根据id查询自媒体文章
        WmNews wmNews = wmNewsMapper.selectById(id);

        //判断文章存在且状态必须为待审核
        if (wmNews == null || !wmNews.getStatus().equals(WmNews.Status.SUBMIT.getCode())) {
            return;
        }

        //抽取文章的图片内容
        List<byte[]> imageList = getImagesFromContent(wmNews);

        //抽取文章的文本内容
        List<String> textList = getTextFromContent(imageList, wmNews);

        /**
         * 自定义敏感词审核
         */
        boolean result = handleSensitiveResult(textList, wmNews);
        if (!result) {
            return;//退出
        }

        //提交文本给阿里云内容检测，根据检测结果修改文章的状态
        try {
            if (CollectionUtils.isNotEmpty(textList)) {
                Map resultMap = greenTextScan.greeTextScan(textList);
                boolean flag = handleScanResult(resultMap, wmNews);
                if (!flag) {
                    return;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        //提交图片给阿里云内容检测，根据检测结果修改文章的状态
        try {
            if (CollectionUtils.isNotEmpty(imageList)) {
                Map resultMap = greenImageScan.imageScan(imageList);
                boolean flag = handleScanResult(resultMap, wmNews);
                if (!flag) {
                    return;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        //判断发布时间是否大于当前时间，代表定时发布，修改文章状态8
        if (wmNews.getPublishTime() != null && wmNews.getPublishTime().after(new Date())) {
            wmNews.setStatus(WmNews.Status.SUCCESS.getCode());
            wmNews.setReason("审核通过，待发布");
            wmNewsMapper.updateById(wmNews);

            wmNewTaskService.addTaskToList(wmNews);
            return; //注意：必须退出
        }

        //把自媒体文章导入到App文章库，修改文章状态为9，代表发表完成
        publishArticle(wmNews);

        log.info("开始发送同步信息");
        kafkaTemplate.send(MQConstants.WM_NEW_UP_ES_TOPIC,wmNews.getArticleId().toString());
    }

    /**
     * 自定义敏感词审核
     *
     * @param textList
     * @param wmNews
     * @return
     */
    private boolean handleSensitiveResult(List<String> textList, WmNews wmNews) {
        boolean flag = true;

        //查询自定义敏感词表
        String sensitiveJson = redisTemplate.opsForValue().get(RedisConstants.SENSITIVE_KEY);
        List<String> wordList = null;
        if (StringUtils.isEmpty(sensitiveJson)) {
            List<WmSensitive> sensitiveList = wmSensitiveMapper.selectList(null);

            if (CollectionUtils.isNotEmpty(sensitiveList)) {
                //提取敏感词
                wordList = sensitiveList.stream().map(WmSensitive::getSensitives).collect(Collectors.toList());
                //存入Redis缓存
                redisTemplate.opsForValue().set(RedisConstants.SENSITIVE_KEY, JsonUtils.toString(wordList));
            }
        } else {
            wordList = JsonUtils.toList(sensitiveJson, String.class);
        }

        //构建敏感词库
        SensitiveWordUtil.initMap(wordList);
        //匹配词库
        String content = textList.stream().collect(Collectors.joining(""));
        Map<String, Integer> matchWords = SensitiveWordUtil.matchWords(content);

        if (matchWords != null && matchWords.size() > 0) {
            //文章出现违规
            wmNews.setStatus(WmNews.Status.FAIL.getCode());
            wmNews.setReason("审核不通过，存在违规内容：" + matchWords.keySet());
            wmNewsMapper.updateById(wmNews);
            flag = false;
        }

        return flag;

    }

    /**
     * 发布自媒体文章到App库
     *
     * @param wmNews
     */
    public void publishArticle(WmNews wmNews) {
        ArticleDto dto = BeanHelper.copyProperties(wmNews, ArticleDto.class);

        //判断article_id是否有值，有值代表修改App文件
        if (wmNews.getArticleId() != null) {
            dto.setId(wmNews.getArticleId());
        }

        //查询作者信息
        WmUser wmUser = wmUserMapper.selectById(wmNews.getUserId());
        if (wmUser != null) {
            dto.setAuthorId(Long.valueOf(wmUser.getId()));
            dto.setAuthorName(wmUser.getName());
        }

        //查询频道信息
        WmChannel channel = wmChannelMapper.selectById(wmNews.getChannelId());
        if (channel != null) {
            dto.setChannelId(channel.getId());
            dto.setChannelName(channel.getName());
        }

        //封面类型
        dto.setLayout(wmNews.getType());
        dto.setFlag((byte) 0);
        dto.setLikes(0);
        dto.setCollection(0);
        dto.setComment(0);
        dto.setViews(0);

        ResponseResult<Long> responseResult = feign.save(dto);
        if (responseResult.getCode().equals(200)) {
            Long articleId = responseResult.getData();

            //修改自媒体文章的article_id值
            wmNews.setArticleId(articleId);
            //状态改为已发布
            wmNews.setStatus(WmNews.Status.PUBLISHED.getCode());
            wmNews.setReason("文章已经成功发布");
            wmNewsMapper.updateById(wmNews);
        }
    }

    /**
     * 处理检测结果
     *
     * @param resultMap
     * @param wmNews
     * @return
     */
    private boolean handleScanResult(Map resultMap, WmNews wmNews) {
        String suggestion = (String) resultMap.get("suggestion");
        boolean flag = false;
        if ("pass".equals(suggestion)) {
            flag = true;
        }
        if ("block".equals(suggestion)) {
            //修改文章状态为失败
            wmNews.setStatus(WmNews.Status.FAIL.getCode());
            wmNews.setReason("审核不通过，存在违规内容");
            wmNewsMapper.updateById(wmNews);
        }
        if ("review".equals(suggestion)) {
            //修改文章状态为人工审核
            wmNews.setStatus(WmNews.Status.ADMIN_AUTH.getCode());
            wmNews.setReason("内容存在可疑，待人工审核");
            wmNewsMapper.updateById(wmNews);
        }
        return flag;
    }

    /**
     * 从文章提取所有图片（包含封面和内容）
     *
     * @param wmNews
     * @return
     */
    private List<byte[]> getImagesFromContent(WmNews wmNews) {

        List<byte[]> imageList = new ArrayList<>();
        //内容
        if (StringUtils.isNotEmpty(wmNews.getContent())) {
            List<Map> list = JsonUtils.toList(wmNews.getContent(), Map.class);
            for (Map map : list) {
                if (map.get("type").equals("image")) {
                    String url = (String) map.get("value");
                    byte[] image = downloadByUrl(url);
                    imageList.add(image);
                }
            }
        }

        if (StringUtils.isNotEmpty(wmNews.getImages())) {
            String[] split = wmNews.getImages().split(",");
            for (String url : split) {
                byte[] image = downloadByUrl(url);
                imageList.add(image);
            }
        }
        return imageList;
    }

    private byte[] downloadByUrl(String url) {
        url = url.replace(readPath, "");
        String path = url.substring(1);
        return storageService.downLoadFile(path);
    }

    /**
     * 从文章提取所有文本（标题，内容文本，标签）
     *
     * @param wmNews
     * @return
     */
    private List<String> getTextFromContent(List<byte[]> imageList, WmNews wmNews) {

        List<String> textList = new ArrayList<>();
        //标题
        if (StringUtils.isNotEmpty(wmNews.getTitle())) {
            textList.add(wmNews.getTitle());
        }
        //标签
        if (StringUtils.isNotEmpty(wmNews.getLabels())) {
            textList.add(wmNews.getLabels());
        }

        if (StringUtils.isNotEmpty(wmNews.getContent())) {
            List<Map> maps = JsonUtils.toList(wmNews.getContent(), Map.class);
            for (Map map : maps) {
                if (map.get("type").equals("text")) {
                    textList.add((String) map.get("value"));
                }
            }
        }

        if (CollectionUtils.isNotEmpty(imageList)) {
            for (byte[] bytes : imageList) {
                InputStream inputStream = new ByteArrayInputStream(bytes);
                try {
                    BufferedImage image = ImageIO.read(inputStream);
                    String result = tesseract.doOCR(image);
                    if (StringUtils.isNotEmpty(result)) {
                        textList.add(result);
                    }
                } catch (Exception e) {
                    log.error("ORC无法识别：" + e.getMessage());
                }
            }
        }

        return textList;
    }
}


